/*******************************************************************

   DetachWindow.c
	
	Does detach itself from the starting process and open a simple
	window with some easy gadgets.
	
	To do this detaching we need 2 functions more and since I want
	not change our ModuleEntry.c for this, I must name the first
	function OwnWindow(). 
	
	You may also refer to the IconClock module of the SDK for 
	an other example.
	
	Use ARTM, SnoopDos or similar if you want to check, that really
	an own process is running...				
					
*********************************************************************/
#define PARENT
#include "/includes/Window.h"

// now we need some other variables than in our structure
// WindowHandle...

typedef struct _PassingData
{
	ULONG a4;                 // to store a4 (module is a4 relative)
	struct Library *library;  // to store a pointer to dopus5.library 
	struct Library *module;   // to store a pointer to this module
	IPCData *ipc;             // to store our NEW handle
	
	char args[256];           // since we want to use the args in our
	                          // detached process, we have to copy it
	
	struct Screen *screen;
}  PassingData;

/********************************************************************/
// locale prototypes

ULONG __asm __saveds New_Proc_Startup( register __a0 IPCData *ipc,
                                       register __a1 PassingData *pd );
													
void __saveds New_Proc( void );

BOOL OpenDOpusWin( WindowHandle *wh );  // function not changed

BOOL HandleWindow( WindowHandle *wh );  // function not changed

/********************************************************************/
// this is not the same function like before !
// it is the first special function we need...

void OwnWindow( STRPTR args, struct Screen *screen )
{
	IPCData *new_proc = NULL;
	PassingData *pd;
	
	if( (pd = AllocMemH(mempool, sizeof(PassingData))) ) // allocate some memory
	  {
		  pd->screen = screen;          // store the screen pointer
		  strcpy( pd->args, args );     // store our arguments
		  
		  // now some special stuff, but everything is needed here...
		  pd->a4      = getreg( REG_A4 ); 
		  pd->module  = (struct Library *) getreg( REG_A6 );
		  pd->library = DOpusBase;
		  
		  // now we are ready to call IPC_Launch()
		  IPC_Launch( 0, 
		              &new_proc,        // pointer to pointer to the IPC of the new process, for storing...
						  "ExampleWindow",  // name of the new process
						  (ULONG) New_Proc, // entrypoint of the new process
						  4096,             // stack to use
						  (ULONG) pd,       // data to pass to the new process
						  DOSBase );        // pointer to dos.library
						  
			if( !new_proc )              // if detaching failed...
			     FreeMemH( pd );
		}
}

// let's do now the second special function

ULONG __asm __saveds New_Proc_Startup( register __a0 IPCData *ipc,
                                       register __a1 PassingData *pd )
{
	// you may use this function also to setup things for your
	// main process, but you should not call any IPC functions here !
	// we do only the minimum required..., but you will get some small
	// warnings from your compiler. Just ignore them now - they does
	// not appear, if we would do here some more things... 
	
	struct Library *DOpusBase; 

	// fix A4
	putreg( REG_A4, pd->a4 );

	// store IPC pointer
	pd->ipc = ipc;

	// get dopus.library - one warning now
	DOpusBase = pd->library;

   // now may follow your initialization
	
	// if something fails and you must quit, you should do:
	// return FALSE;

   // increase our library counter, so we can not be flushed
	// do not forget to decrease it, if your detached process ends 
	pd->module->lib_OpenCnt++;
	
	return TRUE; // all was successfully
} 
	

void __saveds New_Proc( void )
{
	// this is now just the same like until now our OwnWindow() function
	
	WindowHandle          *wh;
	PassingData           *pd;
	STRPTR                 args;
	IPCData               *ipc;
	struct Library        *DOpusBase;
	
	// but we must do some additional things 
	
	// get dopus library
	if( !(DOpusBase = (struct Library *) FindName(&((struct ExecBase *)*((ULONG *)4))->LibList, "dopus5.library")) )
		return;
	
	// do startup
	ipc = IPC_ProcStartup( (ULONG *) &pd, New_Proc_Startup );

	// fix A4 so we can access global data in the module (eg library bases)
	putreg( REG_A4, pd->a4 );

	// something failed until now ?
	if( !ipc )
	{
		if( pd )
		  {
			  IPC_Free( pd->ipc ); // possible it has a value here 
		     FreeMemH( pd );      // free our memory
		  }
			  
		return;
	}
		
	if( (wh = AllocMemH(mempool, sizeof(WindowHandle))) ) // allocate some memory
	  {
		  // we copy now our values, if you allocate for launching the real
	     // structure you need, you must not do this of course... :)

	     
		  wh->screen = pd->screen;     // store the screen pointer
		  strncpy( wh->buffer, pd->args, 30 ); // copy our args - limited through our size of wh->buffer...
		  wh->buffer[30] = NULL;       // terminate our string
		  args = wh->buffer;
		  
		  // now we can free our PassingData...
		  FreeMemH( pd );
		  
		  // now it is really the same excluding the end ...
		  
		  if( OpenDOpusWin(wh) )   // open the window
	       {
				 // we copy now the arguments into the text gadget
		       // if we have supplied some...
				 
		       SetGadgetValue( wh->olist, GADGET_ID_TEXT, (ULONG) args );
				 				 				 
		       while( TRUE ) 
			      {
						// I use here Wait(), so it is easier with the changes
				 
				      wh->signals = Wait( 1 << wh->win->UserPort->mp_SigBit );   // wait for window events
						                				
				      if( wh->signals & 1 << wh->win->UserPort->mp_SigBit )
					        if( HandleWindow(wh) )
							       break;		// does end the while loop									   
					 
			      }
			 
		       CloseConfigWindow( wh->win ); 
			 }
			 
		  FreeMemH( wh ); // free our memory
	  }
	
	// since we are here a detached process, we must do some other cleanup too
	IPC_Free( ipc );
	
	// and decrease our Library access counter, since we have increased it before
	( (struct Library *) getreg(REG_A6) )->lib_OpenCnt--;   
	  					  
}

/********************************************************************/
// This function does open our window. We could have done this in the
// function OwnWindow() too, but we need this function later again.

BOOL OpenDOpusWin( WindowHandle *wh )
{
	NewConfigWindow ncfgwin;     // we need a NewConfigWindow structure too
	                             // of couse you could also allocate it with
										  // AllocMemH()...
	
	// and have to fill it
	
	ncfgwin.nw_Parent = wh->screen;  // open on this screen
	
	// getting a localized title...
	ncfgwin.nw_Title  = DOpusGetString( locale, MSG_WINDOW_TITLE );
	
	ncfgwin.nw_Dims   = &cfgwin; // a pointer to the ConfigWin structure
	ncfgwin.nw_Locale = locale;  // the module locale pointer (from modinit.c)
	ncfgwin.nw_Port   = NULL;    // we doesn't supply a port
	ncfgwin.nw_Font   = NULL;    // just taking the screen font
	ncfgwin.nw_Flags  = WINDOW_REQ_FILL      | // fill with stripple pattern
	                    WINDOW_AUTO_KEYS     | // handle keys automatic
							  WINDOW_SCREEN_PARENT;  // nw_Parent points to a screen
	
	if( (wh->win = OpenConfigWindow(&ncfgwin)) )   // open the window
	  {
		  if( (wh->olist = AddObjectList(wh->win, odef)) ) // add the gadgets
		     	 return TRUE;
					
		  CloseConfigWindow( wh->win );	//	in error case do not forget :-)
	  }
	
	return FALSE;
}


/********************************************************************/
// we does only close the window, if the closegadget was pressed
// if you want to close it within a gadget, you must only in the
// right case set "stop" to TRUE

BOOL HandleWindow( WindowHandle *wh )
{
	 BOOL stop = FALSE;
	 ULONG value;
	 
	 while( !stop && (wh->imsg = GetWindowMsg(wh->win->UserPort)) )
		{
			switch( wh->imsg->Class )  // let's handle the IDCMP
			  {
				  case IDCMP_GADGETUP:
				                          switch( GET_ID(wh->imsg) )
	                                     {
														 case GADGET_ID_CYCLE:  // we copy simply the same text to the text gadget
			
			                                                         value = GetGadgetValue( wh->olist, GADGET_ID_CYCLE ) + MSG_CLICK_ME;
										                                    SetGadgetValue( wh->olist, GADGET_ID_TEXT, (ULONG) DOpusGetString(locale, value) );
										                                    break;
			
			                                  case GADGET_ID_OKAY:   // doing a message
			                                                         
																						SetGadgetValue( wh->olist, GADGET_ID_TEXT, (ULONG) DOpusGetString(locale, MSG_OKAY_DONE) );
										                                    break;
										 			
			                                  case GADGET_ID_CANCEL: 
			                                                         SetGadgetValue( wh->olist, GADGET_ID_TEXT, (ULONG) DOpusGetString(locale, MSG_CANCEL_DONE) );
										                                    break;
		                                  }
																 
												  break;
									 
				  case IDCMP_CLOSEWINDOW:
				                          // we can not simply return here, the IntuiMessage must replied first
												  
									           stop = TRUE;
												  break;									 
			  }
								 
			ReplyWindowMsg( wh->imsg );  
							  
			// remember: You should not use any other routines
			// to get/reply the messages of this window than
			// GetWindowMsg() and ReplyWindowMsg() !!
	   }
						  	 
    return stop;
}